// -*-mode:c++; coding:utf-8-*-

#include "logger.hpp"

#include "session_manager.hpp"

namespace xbase
{
	void session_manager::async_connect(const endpoint_type &endpoint, handler_type handler)
	{
		boost::system::error_code ec;
		session_ptr ptr;

		boost::mutex::scoped_lock lock(m_mutex);
		map_type::iterator it = m_sessions_connected.find(endpoint);
		if(it != m_sessions_connected.end())
		{
			ptr = it->second;

			lock.unlock();

			this->get_upper_level_service().dispatch(boost::bind(handler,
				ptr, ec));
			return;
		}

		handler_list &list = m_requests[endpoint]; // 如果不存在，则立即创建
		bool is_connecting = (! list.empty());	   // 已经有请求并正在连接
		list.push_back(handler);

		lock.unlock();

		if(! is_connecting)
		{
			this->get_lower_level_service().dispatch(boost::bind(&this_type::active_connect,
				this_ptr(),
				endpoint));
		}
	}

	void session_manager::close()
	{
		session_type::on_closed_handler_type null_handler;
		boost::mutex::scoped_lock lock(m_mutex);
		map_type tmp;
		tmp.swap(m_sessions_connected);
		lock.unlock();

		for(map_type::iterator it = tmp.begin();
			it != tmp.end(); ++it)
		{
			// 重置on_closed回调函数，在该函数中就将其删除（以免回调删除时报错）
			it->second->set_on_closed_handler(null_handler);
			it->second->close();
		}
	}

	void session_manager::on_session_closed(endpoint_type endpoint)
	{
		boost::mutex::scoped_lock lock(m_mutex);
		map_type::iterator it = m_sessions_connected.find(endpoint);
		const bool exists = (it != m_sessions_connected.end());
		if(exists)
		{
			m_sessions_connected.erase(it);
		}
		
		LOG_IF_ELSE(exists,
			    DEBUG,
			    "session_manager<>::on_session_closed: remove session "
			    << endpoint,
			    ERROR,
			    "session_manager<>::on_session_closed: not found session "
			    << endpoint);
	}
	
	void session_manager::on_session_connected(endpoint_type ep, session_ptr ptr, const error_code &ec)
	{
		boost::mutex::scoped_lock lock(m_mutex);
		
		if(! ec)
		{
			// 先在已连接列表中注册，以便其它查询可以获得
			std::pair<map_type::iterator, bool> ret =
				m_sessions_connected.insert(map_type::value_type(ep, ptr));
			if(! ret.second) // 已经有了，则记录错误，并用新的代替它
			{
				ret.first->second = ptr;
				LOG(ERROR, "session_manager<>::on_session_connected: "
				    " session " << ep << " duplicated");
			}
			// 连接且注册成功后，才设置回调函数，以管理session的关闭
			ptr->set_on_closed_handler(this->get_lower_level_service().wrap(boost::bind(&this_type::on_session_closed,
											  this_ptr(),
											  ep)));
			ptr->start();
		}
		
		const error_code e = ec; // make a local copy
		request_map_type::iterator p_list = m_requests.find(ep);
		handler_list list;
		list.swap(p_list->second);
		m_requests.erase(p_list);

		lock.unlock();
		
		LOG_IF_ELSE((! ec),
			    DEBUG,
			    "session_manager<>::on_session_connected: new session "
			    << ep << " connected, handler number to dispatch = " << list.size(),
			    DEBUG,
			    "session_manager<>::on_session_connected: connected to " << ep << " error - "
			    << ec << " : " << ec.message()
			    << ", handler number to dispatch = " << list.size());

		while(! list.empty())
		{
			this->get_upper_level_service().dispatch(boost::bind(list.front(), ptr, e));
			list.pop_front();
		}
	}
} // namespace xbase
